package com.yunji.coupon.dao.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yunji.common.base.BaseDaoImpl;
import com.yunji.common.utils.TimeUtils;
import com.yunji.coupon.bo.CouponReceiveTimesBO;
import com.yunji.coupon.bo.ModifyCouponStatusBO;
import com.yunji.coupon.dao.ICouponDao;
import com.yunji.coupon.doamin.CouponDO;
import com.yunji.coupon.dto.CouponListDTO;
import com.yunji.coupon.dto.CouponPageDTO;
import com.yunji.coupon.enums.CouponStatusEnum;
import com.yunji.coupon.mapper.ICouponMapper;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * @author : peter-zhu
 * @date : 2024/10/23 20:46
 * @description : TODO
 **/
@Repository
public class CouponDaoImpl extends BaseDaoImpl<ICouponMapper, CouponDO> implements ICouponDao {

    /**
     * @author : peter-zhu
     * @date : 2024/10/29 9:39
     * @description : 查询未使用有效或者未使用无效的优惠券
     */
    private static LambdaQueryWrapper<CouponDO> buildStatusLambdaQuery(Set<Integer> statusSet) {
        LambdaQueryWrapper<CouponDO> query = new LambdaQueryWrapper<>();
        if (CollectionUtils.isEmpty(statusSet)) {
            return query;
        }
        Date now = new Date();
        query.nested(a -> {
            if (statusSet.contains(CouponStatusEnum.INVALID.getCode())) {
                a.or().nested(q -> q.or().le(CouponDO::getValidPeriodE, now)
                        .eq(CouponDO::getCouponStatus, CouponStatusEnum.UN_USED.getCode()));
                statusSet.remove(CouponStatusEnum.INVALID.getCode());
            }
            if (statusSet.contains(CouponStatusEnum.UN_USED.getCode())) {
                //.le(CouponDO::getValidPeriodS, now)
                a.or().nested(q -> q.or()
                        .ge(CouponDO::getValidPeriodE, now)
                        .eq(CouponDO::getCouponStatus, CouponStatusEnum.UN_USED.getCode()));
                statusSet.remove(CouponStatusEnum.UN_USED.getCode());
            }
            boolean empty = CollectionUtils.isEmpty(statusSet);
            a.or(!empty).in(!empty, CouponDO::getCouponStatus, statusSet);
        });
        return query;
    }

    /**
     * @author : peter-zhu
     * @date : 2024/10/25 15:44
     * @description : 统计某个用户领取某个优惠券的次数
     */
    @Override
    public Integer receiveTimes(CouponReceiveTimesBO bo) {
        LocalDate now = LocalDate.now();
        return lambdaQuery().eq(CouponDO::getCouponTmplId, bo.getCouponTmplId()).
                eq(CouponDO::getUserId, bo.getUserId()).
                between(bo.isDay(), CouponDO::getCreateTime, TimeUtils.getMinDay(now), TimeUtils.getMaxDay(now)).count().intValue();
    }

    @Override
    public List<CouponDO> couponList(CouponListDTO dto) {
        LambdaQueryWrapper<CouponDO> query = buildStatusLambdaQuery(dto.getStatusList());
        query.eq(dto.getUserId() != null, CouponDO::getUserId, dto.getUserId());
        return list(query);
    }

    @Override
    public List<CouponDO> couponList(CouponPageDTO dto) {
        return list(getQueryWrapper(dto));
    }

    private static LambdaQueryWrapper<CouponDO> getQueryWrapper(CouponPageDTO dto) {
        LambdaQueryWrapper<CouponDO> query = buildStatusLambdaQuery(dto.getStatusList());
        query.eq(dto.getCouponTmplId() != null, CouponDO::getCouponTmplId, dto.getCouponTmplId());
        return query;
    }

    @Override
    public List<CouponDO> couponPageList(CouponPageDTO dto) {
        return pageList(dto, getQueryWrapper(dto));
    }

    @Override
    public boolean modifyCouponStatus(ModifyCouponStatusBO status) {
        return lambdaUpdate().set(CouponDO::getCouponStatus, status.getNewStatus()).eq(CouponDO::getCouponStatus, status.getStatus())
                .eq(CouponDO::getCouponId, status.getCouponId()).update();
    }

    @Override
    public boolean recall(Long tempId) {
        Date now = new Date();
        return lambdaUpdate().set(CouponDO::getCouponStatus, CouponStatusEnum.RECALL.getCode())
                .le(CouponDO::getValidPeriodS, now).ge(CouponDO::getValidPeriodE, now)
                .eq(CouponDO::getCouponStatus, CouponStatusEnum.UN_USED.getCode())
                .eq(CouponDO::getCouponTmplId, tempId).update();
    }
}
